<?php

declare(strict_types=1);

namespace catcher\platform;

use catcher\Utils;
use DateTime;
use think\facade\Log;
use catchAdmin\basics\model\Shop as ShopModel;
use catchAdmin\order\model\OrderGetRecords as OrderGetRecordsModel;
use catchAdmin\order\model\OrdersTemp as OrdersTempModel;

abstract class BasePlatformService
{
    /**
     * 起始查询时间
     * @var string
     */
    protected $startDate;

    /**
     * 查询时间
     * @var DateTime
     */
    protected $getAt;

    /**
     * 每次任务的执行时间
     * @var DateTime
     */
    protected $now;

    /**
     * 查询平台
     * @var string
     */
    protected $platform;

    /**
     * 接口名称
     * @var string
     */
    protected $interface;

    /**
     * 接口执行回滚时间
     * @var integer
     */
    protected $minute;

    /**
     * 时间格式化格式
     */
    protected const DATE_FORMAT = "Y-m-d\TH:i:s.\\0\\0\\0\\Z";

    protected const DATE_DEFAULT_FORMAT = "Y-m-d H:i:s";

    public function __construct($interface, $startDate, $minute = -9)
    {
        $className = Utils::classBasename(get_called_class());
        $this->startDate = $startDate;
        $this->platform = substr($className, 0, strrpos($className, 'Service'));
        $this->interface = $interface;
        $this->now = (new DateTime)->setTimezone(new \DateTimeZone('UTC'));
        $this->minute = $minute;
    }

    /**
     * 查询该任务上一次的执行时间
     * @param $platform
     * @param $interface
     * @param $shopId
     * @return mixed
     */
    protected function getLastTime($platform, $interface, $shopId)
    {
        return OrderGetRecordsModel::where([
            'platform_name' => $platform,
            'interface_name' => $interface,
            'shop_basics_id' => $shopId
        ])
            ->order('created_at', 'desc')
            ->value('created_at');
    }

    /**
     * 添加平台订单到临时表
     * @param string $orderNo 平台订单号
     * @param array $order 订单信息
     * @param array $platform 平台
     * @param int $shopId 店铺ID
     * @param bool $replace 存在是否替换，默认不替换
     * @date 2021/02/23
     * @return bool
     * @author salgee
     */
    public function pushOrderToTemp($orderNo, $order = [], $platform = [], $shopId = 0, $replace = false, $orderNo2 = '')
    {
        // 如果订单已存在则直接跳过
        $hasOrder = OrdersTempModel::hasOrder($orderNo, $shopId, $platform['id']);
        if (!$replace && $hasOrder) return false;
        if ($replace && $hasOrder) {
            OrdersTempModel::get([
                "order_no" => $orderNo,
                "shop_id" => $shopId
            ])->save([
                "is_sync_order" => OrdersTempModel::SYNC_ORDER_N,
                "order_info" => json_encode($order),
            ]);
        } else {
            OrdersTempModel::create([
                "order_no" => $orderNo,
                "order_no2" => $orderNo2,
                "shop_id" => $shopId,
                "platform_name" => $platform['name'],
                "platform_id" => $platform['id'],
                "order_info" => json_encode($order),
            ]);
        }
        return true;
    }

    /**
     * 查询需要拉取订单的店铺
     * @param $platformId
     * @param $shopId
     * @return mixed
     */
    public function getShop($platformId, $shopId = 0)
    {
        $shop = ShopModel::field(['id', 'shop_name', 'platform_parameters'])
            ->where(['platform_id' => $platformId, 'is_status' => 1]);
        if ($shopId != 0) {
            $shop->where(['id' => $shopId]);
        }
        return $shop->select();
    }

    abstract public function setShop();

    /**
     * 同步一条订单数据
     * @param OrdersTempModel $ordersTempModel 一条订单数据
     * @date 2020/08/20
     * @return bool
     *@author longli
     */
    abstract public function syncOrder(OrdersTempModel $ordersTempModel);

    abstract public function getOrderList($params = [], $replace = false);

    /**
     * 同步订单到 order 表
     * @param int $platformId 平台id, 同步指定平台订单， 默认同步所有订单
     * @param string $startDate 从什么时间开始同步，默认是所有
     * @param bool $force 是否强制同步，默认不强制同步
     * @date 2021/02/23
     * @author salgee
     */
    public function syncOrderByAccount($platformId = [], $startDate = null, $force = false, $id = '')
    {
        Log::info(sprintf("通过平台同步店铺订单到订单表，参数: 【%s】", json_encode(func_get_args())));
        $where = [];
        if (!$force) $where[] = ['is_sync_order', '=', OrdersTempModel::SYNC_ORDER_N];
        if (!empty($platformId)) $where[] = ['platform_id', 'in', $platformId];
        if (!empty($id)) $where[] = ['id', '=', $id];
        if (!empty($startDate)) $where[] = ['create_time', '>=', $startDate];
        OrdersTempModel::where($where)->chunk(10, function ($result) {
            foreach ($result as $item) {
                try {
                    if ($this->syncOrder($item)) {
                        $item->is_sync_order = OrdersTempModel::SYNC_ORDER_Y;
                        $item->sync_at = time();
                        $item->updated_at = time();
                        $item->save();
                    }
                } catch (\Exception $e) {
                    $message = sprintf(
                        $this->getPlatform() . " 店铺【%d】订单【%s】同步订单，异常信息:【%s】",
                        $item->shop_id,
                        $item->order_no,
                        $e->getCode() . ':' . $e->getMessage() .
                            ' in ' . $e->getFile() . ' on line ' . $e->getLine()
                    );
                    Log::info($message);
                    // 改为同步异常订单
                    $item->is_sync_order = OrdersTempModel::SYNC_ORDER_E;
                    $item->updated_at = time();
                    $item->save();
                    throw new \Exception($message);
                    //                    return $message;
                }
            }
        });
    }

    /**
     * @param $count
     * @param $shopId
     * @return int|string
     */
    public function saveGetOrderRecord($count, $shopId)
    {
        // 写入接口调用记录
        return OrderGetRecordsModel::insert([
            'platform_name' => $this->getPlatform(),
            'interface_name' => $this->getInterface(),
            'get_at' => $this->getGetAt($shopId)->getTimestamp(),
            'get_count' => $count,
            'shop_basics_id' => $shopId,
            'created_at' => $this->getNow()->getTimestamp(),
            'updated_at' => time()
        ]);
    }

    /**
     * 格式时间为 ISO8601 格式
     * @param string $time 时间戳，或者字符时间，默认为当前时间
     * @param string $suffix 后缀
     * @date 2021/02/24
     * @author salgee
     * @return string
     */
    public function formatTimeToDate($time = '', $suffix = '')
    {
        $time = $time ?: time();
        if (!is_numeric($time)) $time = strtotime($time);
        return str_replace(' ', 'T', date('Y-m-d H:i:s', $time)) . $suffix;
    }

    /**
     * 解析 ISO8601 格式时间为中国时间
     * @param string $time 时间
     * @date 2021/02/24
     * @author salgee
     * @return string
     */
    public function parseTimeToDate($time)
    {
        if (is_numeric($time) && strlen($time) == 13) $time = intval($time / 1000);
        if (!is_numeric($time) && strtotime($time) === false) return null;
        return date('Y-m-d H:i:s', is_numeric($time) ? $time : strtotime($time));
    }

    /**
     * 查询指定店铺ID的平台配置
     * @param $shopId
     * @return mixed
     */
    public function getShopPlatform($shopId)
    {
        return App(ShopModel::class)->findBy($shopId, ['platform_parameters'])['platform_parameters'];
    }

    /**
     * @return DateTime
     */
    public function getGetAt($shopId)
    {
//        $this->getAt = $this->getLastTime($this->platform, $this->interface, $shopId);
//        // 设置时间为后一次调用的时间之前$minute分钟
//        $this->getAt = empty($this->getAt) ? (new DateTime($this->startDate)) : (new DateTime)->setTimestamp($this->getAt)->modify($this->minute . ' minute')
//            ->setTimezone(new \DateTimeZone('UTC'));
        $this->getAt = $this->getLastTime($this->platform, $this->interface, $shopId) ?: $this->getStartDate();
        // 设置时间为后一次调用的时间之前$minute分钟
        $this->getAt = !empty($this->startDate) ? (new DateTime($this->getStartDate())) : (new DateTime)->setTimestamp($this->getAt);
        $this->getAt = $this->getAt->modify($this->minute . ' minute')->setTimezone(new \DateTimeZone('UTC'));
        return $this->getAt;
    }

    /**
     * @return DateTime
     */
    public function getNow()
    {
        return $this->now;
    }

    /**
     * @return string
     */
    public function getStartDate(): string
    {
        // 开始时间没有传递则取当前时间
        return $this->startDate = $this->startDate ?: (new DateTime)->setTimezone(new \DateTimeZone('PRC'))
            ->format('Y-m-d H:i:s');
    }

    /**
     * @return string
     */
    public function getPlatform(): string
    {
        return $this->platform;
    }

    /**
     * @return string
     */
    public function getInterface(): string
    {
        return $this->interface;
    }
}
